package com.ligq.vbasedemo.decode

import android.media.MediaCodec
import android.media.MediaFormat
import android.util.Log
import android.view.Surface
import java.io.*

class H264Player constructor(private var surface: Surface) : Runnable {
    private var ins: InputStream? = null
    private var mediaCodec: MediaCodec? = null

    @Volatile
    private var stopPlay = true

    constructor(ins: InputStream, surface: Surface) : this(surface) {
        this.ins = ins
        this.surface = surface
    }

    constructor(path: String, surface: Surface) : this(surface) {
        this.ins = FileInputStream(File(path))
        this.surface = surface
    }

    init {
        mediaCodec = MediaCodec.createDecoderByType("video/avc")
        val mediaFormat = MediaFormat.createVideoFormat("video/avc", 400, 600)
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15)
        mediaCodec!!.configure(mediaFormat, surface, null, 0)
    }

    @Throws(IOException::class)
    fun getBytes(ins: InputStream?): ByteArray {
        val `is`: InputStream = DataInputStream(ins)
        var len: Int
        val size = 1024
        val bos = ByteArrayOutputStream()
        var buf = ByteArray(size)
        while (`is`.read(buf, 0, size).also { len = it } != -1) bos.write(buf, 0, len)
        buf = bos.toByteArray()
        return buf
    }

    private fun decodeH264() {
        val bytes = getBytes(ins)
        var startIndex = 0
        val info = MediaCodec.BufferInfo()
        while (!stopPlay) {
            val nextFrameStart = findByFrame(bytes, startIndex + 2, bytes.size)
            //获取空闲的容器索引
            val inIndex = mediaCodec?.dequeueInputBuffer(10000)
            if (inIndex != null && inIndex > 0) {
                //根据索引获取空闲dsp容器
                val byteBuffer = mediaCodec?.getInputBuffer(inIndex)
                val length = nextFrameStart - startIndex
                if (length < 0 || length > bytes.size) {
                    Log.d("ligq", "decodeH264: 播放完毕，重新播放！！！")
                    break
                }
                //将数据放入到dsp容器中，一帧一帧放入
                byteBuffer?.put(bytes, startIndex, length)
                mediaCodec?.queueInputBuffer(inIndex, 0, length, 0, 0)
                startIndex = nextFrameStart
            }
            val outIndex = mediaCodec?.dequeueOutputBuffer(info, 10000)
            if (outIndex != null && outIndex > 0) {
                //render surface可用传入true
                mediaCodec?.releaseOutputBuffer(outIndex, true)
            }
        }
        mediaCodec?.run {
            flush()
            stop()
            release()
        }
    }

    private fun findByFrame(bytes: ByteArray, start: Int, totalSize: Int): Int {
        for (i in start..totalSize - 4) {
            if (bytes[i].toInt() == 0x00 && bytes[i + 1].toInt() == 0x00 && bytes[i + 2].toInt() == 0x00 && bytes[i + 3].toInt() == 0x01
                || bytes[i].toInt() == 0x00 && bytes[i + 1].toInt() == 0x00 && bytes[i + 2].toInt() == 0x01
            ) {
                return i
            }
        }
        return -1
    }

    fun start() {
        stopPlay = false
        mediaCodec?.start()
        Thread(this).start()
    }

    fun stop() {
        if (!stopPlay) {
            stopPlay = true
        }
    }


    override fun run() {
        decodeH264()
    }
}